package com.example.ccj.b.c.form;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.ccj.R;
import com.example.ccj.b.c.draw.TopBar;
import com.example.ccj.u.LogUtils;
import com.example.ccj.u.StringUtils;
import com.example.ccj.u.ToastUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

/**
 * 表单加载
 * 根据传入的类型通过反射加载或者传入配置加载
 *
 * @author 驰珺
 * whechat   : chijun9
 * create at : 2024/6/24 11:44
 */
public  class CreateFormView extends LinearLayout {
    private static final String TAG = "表单加载";


    public CreateFormView(Context context) {
        super(context);
        initView();
    }

    public CreateFormView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public CreateFormView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    public CreateFormView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();
    }

    LoadStateListener loadStateListener;//表单加载状态

    OptionFormatter optionFormatter;
    LinearLayout fieldContent;

    TopBar topBar;


    private void initView(){
        LayoutInflater.from(getContext()).inflate(R.layout.custom_create_form, this);
        topBar = findViewById(R.id.custom_create_form_top);
        fieldContent = findViewById(R.id.custom_create_form_content);
        topBar.getTopTitle().setGravity(Gravity.CENTER_VERTICAL);
        setOrientation(VERTICAL);
    }

    public NoMergeJavaBean setClass(Class<?> mClass){
        jxClass(mClass,null);
        return new NoMergeJavaBean(inPutDataMap);
    }

    public NoMergeJavaBean setObject(Object obj){
        jxClass(obj.getClass(),obj);
        return new NoMergeJavaBean(inPutDataMap);
    }

    public NoMergeJavaBean setFileConfig(List<FieldConfig> fieldConfigList,OptionFormatter optionFormatter){
        getFormForConfig(fieldConfigList);
        this.optionFormatter = optionFormatter;
        return new NoMergeJavaBean(inPutDataMap);
    }

    /**
     * 传入已初始化的javabean返回类型，可以使用该返回值获取填入数据后的类
     * @param obj 原始数据
     * @param tClass 类型
     * @return 返回数据处理类
     * @param <T> javabean
     */
    public <T> MergeJavaBean<T> setObject(T obj, Class<T> tClass){
        jxClass(tClass,obj);
        return new MergeJavaBean<>(obj,tClass,inPutDataMap);
    }

    public <T> MergeJavaBean<T> setObject(T obj, Class<T> tClass,OptionFormatter optionFormatter){
        jxClass(tClass,obj);
        this.optionFormatter = optionFormatter;
        return new MergeJavaBean<>(obj,tClass,inPutDataMap);
    }

    Map<String,InPutData> inPutDataMap = new HashMap<>();
    Map<String,Map<Integer, List<InPutData>>> superFDataMap = new HashMap<>();//关联字段

    private void jxClass(Class<?> mClass,Object obj){
        LogUtils.d(TAG,"开始解析注释类生成表单");
        Observable.create((ObservableOnSubscribe<InPutData>) e -> {
                    //表单名称
                    MForm mForm = mClass.getAnnotation(MForm.class);
                    if (mForm != null) this.post(() -> topBar.setTitle(mForm.value()));

                    Field[] fields = mClass.getDeclaredFields();

                    for (Field field : fields) {
                        InPutData inPutData;
                        FieldConfig fieldConfig = new FieldConfig();
                        field.setAccessible(true);
                        MFormField formField = field.getAnnotation(MFormField.class);
                        //字段的属性配置
                        if (formField != null && !formField.isSkip()) {
                            fieldConfig.setHint(formField.hint());
                            fieldConfig.setFieldName(formField.value());
                            fieldConfig.setDataName(field.getName());
                            fieldConfig.setNoNull(formField.isNoNUll());
                            fieldConfig.setOnlySelect(formField.isOnlySelect());
                            fieldConfig.setMaxLength(formField.maxLength());
                            fieldConfig.setType(formField.type());
                            fieldConfig.setCanModify(formField.isCanModify());
                            fieldConfig.setOrder(formField.order());
                            fieldConfig.setSuperF(formField.superF());
                            fieldConfig.setOption(formField.option());

                            //字段的值
                            if (obj != null) {
                                String value = String.valueOf(field.get(obj));
                                LogUtils.d("获取值: " + field.getName()+":" + value);
                                if (!StringUtils.isEmpty(value)) fieldConfig.setText(value);
                            }
                            //根据配置解析出字段View
                            inPutData = getInputDataViewForConfig(fieldConfig);

                        } else {
                            continue;
                        }
                        e.onNext(inPutData);
                    }
                    e.onComplete();
                }).subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<InPutData>() {
                    @Override
                    public void onSubscribe(Disposable d) {}
                    @Override
                    public void onNext(InPutData inPutData) {
                        fieldContent.addView(inPutData);
                    }
                    @Override
                    public void onError(Throwable e) {
                        LogUtils.e(TAG,"加载表单失败: ",e );
                        ToastUtils.showShort("加载表单失败：",e.getMessage());
                        if (loadStateListener != null) loadStateListener.onError("加载表单失败: " + e.getMessage());
                    }
                    @Override
                    public void onComplete() {
                        LogUtils.d(TAG,"加载表单成功");
                        if (loadStateListener != null) loadStateListener.onSuccess();
                        sort();
                    }
                });
    }

    /**
     * 放入选项字段回调
     * @param inPutData 字段view
     */
    private void setOptionFieldChangeListener(InPutData inPutData){
        if (optionFormatter == null) return;
        FieldConfig fieldConfig = inPutData.getFieldConfig();
        if (fieldConfig.type == MFormField.DAN_OPTION) {
            fieldConfig.setOptionFormatter(new OptionFormatter() {
                @Override
                public String formatItem(String fileName, @NonNull Object item) {
                    return optionFormatter.formatItem(fileName,item);
                }
                @Override
                public String result(String fileName, int position, @NonNull Object data) {
                    if (superFDataMap != null && superFDataMap.containsKey(fileName)) {
                        Map<Integer, List<InPutData>> listMap = superFDataMap.get(fileName);
                        if (listMap != null){
                            for (Integer i : listMap.keySet()) {
                                List<InPutData> inPutDataList = listMap.get(i);
                                if (inPutDataList != null) {
                                    for (InPutData putData : inPutDataList) {
                                        if (i == position) post(() -> putData.setVisibility(VISIBLE));
                                        else post(() -> putData.setVisibility(GONE));
                                    }
                                }
                            }
                        }
                    }
                    return optionFormatter.result(fileName,position,data);
                }
                @Override
                public Object[] getOption(String fileName) {
                    return optionFormatter.getOption(fileName);
                }
            });
        } else {
            fieldConfig.setOptionFormatter(optionFormatter);
        }
        //放入选项  优先使用注解字段的选项
        if (fieldConfig.option == null || fieldConfig.option.length < 1) {
            if (fieldConfig.optionFormatter != null) fieldConfig.option = optionFormatter.getOption(fieldConfig.dataName);
        }
    }

    /**
     * 解析字段所关联的字段
     * 关联字段写法：[所关联的上级字段名称.选项编号,所关联的上级字段名称.选项编号,。。。。。。。。]
     * @param inPutData 字段
     */
    private void jxGLField(InPutData inPutData){
        FieldConfig fieldConfig = inPutData.getFieldConfig();
        //解析关联字段
        if (!StringUtils.isEmpty(fieldConfig.superF)) {
            String[] gl = fieldConfig.superF.split(",");
            for (String s : gl) jxOneGLField(inPutData,s);
        }
    }

    /**
     * 解析一个关联字段
     * @param inPutData 关联上级字段view
     * @param str 关联说明
     */
    private void jxOneGLField(InPutData inPutData,String str){
        if (!StringUtils.isEmpty(str)) {
            String[] superFArray = str.split("\\.");
            if (superFArray.length != 2) return;
            try {
                int optionNum = Integer.parseInt(superFArray[1]); //选项编号
                Map<Integer, List<InPutData>> listMap;  //选项编号，该编号关联的字段
                List<InPutData> inPutDataList;          //编号关联的字段
                if (superFDataMap.containsKey(superFArray[0])) {
                    listMap = superFDataMap.get(superFArray[0]);
                    if (listMap == null) listMap = new HashMap<>();
                    if (listMap.containsKey(optionNum)) {
                        inPutDataList = listMap.get(optionNum);
                        if (inPutDataList == null) inPutDataList = new ArrayList<>();
                        if (!inPutDataList.contains(inPutData)) inPutDataList.add(inPutData);
                    } else {
                        inPutDataList = new ArrayList<>();
                        inPutDataList.add(inPutData);
                        listMap.put(optionNum,inPutDataList);
                    }
                } else {
                    listMap = new HashMap<>();
                    inPutDataList = new ArrayList<>();
                    inPutDataList.add(inPutData);
                    listMap.put(optionNum,inPutDataList);
                    superFDataMap.put(superFArray[0],listMap);
                }
                inPutData.setVisibility(GONE);//隐藏该关联字段
            } catch (NumberFormatException n) {
                LogUtils.e("转换字段关联上级选项失败: 转换选项编号失败，关联的字段：",str+"，错误：" + n.getMessage());
                if (loadStateListener != null) loadStateListener.onError("加载表单失败- " + "转换字段关联上级选项失败: 转换选项编号失败，关联的字段：" + str+"，错误：" + n.getMessage());
            }
        }
    }

    /**
     * 根据传入的配置列表获取表单
     * @param fieldConfigList 字段配置列表
     */
    private void getFormForConfig(List<FieldConfig> fieldConfigList){
        LogUtils.d(TAG,"根据配置加载表单");
        Observable.create((ObservableOnSubscribe<InPutData>) e -> {
            for (FieldConfig fieldConfig : fieldConfigList) {
                InPutData inPutData = getInputDataViewForConfig(fieldConfig);
                e.onNext(inPutData);
            }
        }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<InPutData>() {
                    @Override
                    public void onSubscribe(Disposable d) {}

                    @Override
                    public void onNext(InPutData inPutData) {
                        fieldContent.addView(inPutData);
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (loadStateListener != null) loadStateListener.onError("加载表单失败- " + e.getMessage());
                        LogUtils.e(TAG,"onError: ", e.getMessage());
                    }

                    @Override
                    public void onComplete() {
                        LogUtils.d(TAG,"根据配置加载表单成功");
                        if (loadStateListener != null) loadStateListener.onSuccess();
                        sort();
                    }
                });
    }

    /**
     * 根据配置生成字段view
     * @param fieldConfig 配置文件
     * @return 字段view
     *
     */
    private InPutData getInputDataViewForConfig(FieldConfig fieldConfig){
        LogUtils.d("字段view关联的字段: " + fieldConfig);
        InPutData inPutData = new InPutData(getContext());
        inPutData.setFieldConfig(fieldConfig);
        setOptionFieldChangeListener(inPutData);
        jxGLField(inPutData);
        inPutDataMap.put(fieldConfig.getDataName(),inPutData);  //放入集合用于排序
        return inPutData;
    }

    /**
     * 排序字段
     */
    public void sort(){
        int n = fieldContent.getChildCount();
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i; j++) {
                View childAt1 = fieldContent.getChildAt(j);
                View childAt2 = fieldContent.getChildAt(j + 1);
                if (childAt1 instanceof InPutData && childAt2 instanceof InPutData) {
                    int orderA = ((InPutData) childAt1).fieldConfig.order;
                    int orderB = ((InPutData) childAt2).fieldConfig.order;
                    if (orderA > orderB) {
                        View childAt = fieldContent.getChildAt(j);
                        fieldContent.removeViewAt(j);
                        fieldContent.addView(childAt,j+1);
                    }
                }
            }
        }
    }

    public static class NoMergeJavaBean {
        Map<String,InPutData> inPutDataMap;
        public NoMergeJavaBean(Map<String,InPutData> inPutDataMap){
            this.inPutDataMap= inPutDataMap;
        }
        public void getData(GetDataListener getDataListener){
            if (!inPutDataMap.isEmpty() && getDataListener!= null) {
                boolean isHaveError = false;
                Map<String,String> map = new HashMap<>();
                for (String s : inPutDataMap.keySet()) {
                    InPutData inPutData = inPutDataMap.get(s);
                    if (inPutData != null) {
                        if (!inPutData.check()) isHaveError = true;
                        map.put(s,inPutData.fieldConfig.text.toString());
                    }
                }
                if (isHaveError) ToastUtils.showShort("请先根据提示修改错误！");
                else getDataListener.onData(map);
            } else {
                ToastUtils.showShort("未创建任何表单字段！");
            }
        }
    }

    public static class MergeJavaBean<T>  {
        T obj;
        Class<T> tClass;
        Map<String,InPutData> inPutDataMap;
        public MergeJavaBean(T obj, Class<T> tClass,Map<String,InPutData> inPutDataMap){
            this.obj = obj;
            this.tClass= tClass;
            this.inPutDataMap= inPutDataMap;
        }

        public T getT(){
            if (inPutDataMap == null) {
                return obj;
            } else {
                boolean isHaveError = false;
                String jsonString = JSON.toJSONString(obj);
                JSONObject jsonObject = JSON.parseObject(jsonString);
                for (String s : inPutDataMap.keySet()) {
                    InPutData inPutData = inPutDataMap.get(s);
                    if (inPutData != null) {
                        if (!inPutData.check()) {
                            isHaveError = true;
                            LogUtils.d("getT: 存在错误" + inPutData.fieldConfig.fieldName);
                        }
                        jsonObject.put(s,inPutData.fieldConfig.text);
                    }
                }

                LogUtils.d("getT: " + jsonObject.toString());
                if (isHaveError) return null;
                return JSON.toJavaObject(jsonObject, tClass);
            }
        }
    }



    public interface GetDataListener{
        void onError(String error);
        void onData(Map<String,String> val);
    }

    public LoadStateListener getLoadStateListener() {
        return loadStateListener;
    }

    public void setLoadStateListener(LoadStateListener loadStateListener) {
        this.loadStateListener = loadStateListener;
    }

    public interface LoadStateListener{
        void onError(String error);
        void onSuccess();
    }
}
